using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.Text;

namespace Universe.WinForms
{
    public class ColorInfo
    {
        Color _TheColor;


        public ColorInfo(Color theColor)
        {
            _TheColor = theColor;
        }


        public ColorInfo(float hue,
                         float luminance,
                         float saturation)
        {
            _TheColor = HSLToRGB(hue, saturation, luminance);
        }


        public Color Color
        {
            get { return _TheColor; }
            set { _TheColor = value; }
        }


        public float Luminance
        {
            get
            {
                float h = 0, s = 0, l = 0;
                RGBToHSL(this.Color, ref h, ref s, ref l);
                return l;
            }
            set
            {
                _TheColor = this.HSLToRGB(Hue, Saturation, value);
            }
        }


        public float Hue
        {
            get
            {
                float h = 0, s = 0, l = 0;
                RGBToHSL(this.Color, ref h, ref s, ref l);
                return h;
            }
            set
            {
                _TheColor = this.HSLToRGB(value, Saturation, Luminance);
            }
        }


        public float Saturation
        {
            get
            {
                float h = 0, s = 0, l = 0;
                RGBToHSL(this.Color, ref h, ref s, ref l);
                return s;
            }
            set
            {
                _TheColor = this.HSLToRGB(Hue, value, Luminance);
            }
        }


        private Color HSLToRGB(float hue,
                               float saturation,
                               float luminance)
        {
            int Red = (int)(luminance * 255.0f);
            int Green = (int)(luminance * 255.0f);
            int Blue = (int)(luminance * 255.0f);
            if (saturation != 0.0)
            {
                float rm1, rm2;

                if (luminance <= 0.5f)
                    rm2 = luminance + luminance * saturation;
                else
                    rm2 = luminance + saturation - luminance * saturation;
                rm1 = 2.0f * luminance - rm2;
                Red = ToRGB1(rm1, rm2, hue + 120.0f);
                Green = ToRGB1(rm1, rm2, hue);
                Blue = ToRGB1(rm1, rm2, hue - 120.0f);
            }

            return Color.FromArgb(Red, Green, Blue);
        } // HSLToRGB()

        private byte ToRGB1(float rm1,
                            float rm2,
                            float rh)
        {
            if (rh > 360.0f)
                rh -= 360.0f;
            else if (rh < 0.0f)
                rh += 360.0f;

            if (rh < 60.0f)
                rm1 = rm1 + (rm2 - rm1) * rh / 60.0f;
            else if (rh < 180.0f)
                rm1 = rm2;
            else if (rh < 240.0f)
                rm1 = rm1 + (rm2 - rm1) * (240.0f - rh) / 60.0f;

            return (byte)(rm1 * 255);
        } // ToRGB1()

        void RGBToHSL(Color inColor,
                      ref float hue,
                      ref float saturation,
                      ref float luminance)
        {
            float Red = (float)inColor.R;
            float Green = (float)inColor.G;
            float Blue = (float)inColor.B;
            float minval = Red;
            if (Green < minval) minval = Green;
            if (Blue < minval) minval = Blue;
            float maxval = Red;
            if (Green > maxval) maxval = Green;
            if (Blue > maxval) maxval = Blue;

            float mdiff = maxval - minval;
            float msum = maxval + minval;

            luminance = msum / 510.0f;
            saturation = 0.0f;
            hue = 0.0f;

            if (maxval == minval)
            {
                saturation = 0.0f;
                hue = 0.0f;
            }
            else
            {
                float rnorm = (maxval - Red) / mdiff;
                float gnorm = (maxval - Green) / mdiff;
                float bnorm = (maxval - Blue) / mdiff;

                if (luminance <= 0.5f)
                    saturation = (mdiff / msum);
                else
                    saturation = (mdiff / (510.0f - msum));

                if (Red == maxval) hue = 60.0f * (6.0f + bnorm - gnorm);
                if (Green == maxval) hue = 60.0f * (2.0f + rnorm - bnorm);
                if (Blue == maxval) hue = 60.0f * (4.0f + gnorm - rnorm);
                if (hue > 360.0f) hue = hue - 360.0f;
            }
        } // RGBToHSL()
        
        
        public static Color Blend(Color fore, Color back, float opacity)
        {
            float
                r = (float) back.R + (fore.R - back.R)*(1 - opacity),
                g = (float) back.G + (fore.G - back.G)*(1 - opacity),
                b = (float) back.B + (fore.B - back.B)*(1 - opacity);
            
            return Color.FromArgb((byte) r, (byte) g, (byte) b);
        }
        
        public int ToInt()
        {
            return
                (int) _TheColor.R
                | (int)(_TheColor.G << 8)
                | (int)(_TheColor.B << 16);
                
        }

        public static string ToHexString(Color color)
        {
            if (color.IsEmpty)
                return null;

            return string.Format("#{0:X2}{1:X2}{2:X2}", color.R, color.G, color.B);
        }

        public static Color ParseHex(string hexColor)
        {
            if (hexColor == null || hexColor.Length == 0)
                return Color.Empty;


            try
            {
                KnownColor kc = (KnownColor)Enum.Parse(typeof(KnownColor), hexColor);
                Color ret = Color.FromKnownColor(kc);
                return ret;
            }
            catch
            {
            }

            if (hexColor[0] == '#')
            {
                if (hexColor.Length > 1)
                    hexColor = hexColor.Substring(1);
                else
                    return Color.Empty;
            }

            int
                r = int.Parse(hexColor.Substring(0, 2), NumberStyles.AllowHexSpecifier),
                g = int.Parse(hexColor.Substring(2, 2), NumberStyles.AllowHexSpecifier),
                b = int.Parse(hexColor.Substring(4, 2), NumberStyles.AllowHexSpecifier);

            return Color.FromArgb(r, g, b);
        }
        
        
    }
}
